1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.hiprenderer.backend.d3d.d3dtexture;
12 version(Windows):
13 version(DirectX):
14 import hip.hiprenderer.backend.d3d.d3drenderer;
15 public import hip.api.renderer.texture;
16 
17 import hip.image;
18 import directx.d3d11;
19 import hip.error.handler;
20 
21 
22 private __gshared ID3D11ShaderResourceView nullSRV = null;
23 private __gshared ID3D11SamplerState nullSamplerState = null;
24 
25 class Hip_D3D11_Texture : IHipTexture
26 {
27     ID3D11Texture2D texture;
28     ID3D11ShaderResourceView resource;
29     ID3D11SamplerState sampler;
30     int width, height;
31     float[4] borderColor;
32     int filter = Hip_D3D11_getTextureFilter(TextureFilter.NEAREST, TextureFilter.NEAREST);
33     int wrap = Hip_D3D11_getWrapMode(TextureWrapMode.REPEAT);
34     bool[] slotsBound;
35 
36     IHipTexture getBackendHandle(){return this;}
37     this()
38     {
39         import hip.hiprenderer:HipRenderer;
40         slotsBound = new bool[HipRenderer.getMaxSupportedShaderTextures()];
41     }
42 
43 
44     bool hasSuccessfullyLoaded(){return width > 0;}
45 
46     void setTextureFilter(TextureFilter mag, TextureFilter min)
47     {
48         filter = Hip_D3D11_getTextureFilter(min, mag);
49         updateSamplerState();
50     }
51     package void updateSamplerState()
52     {
53         D3D11_SAMPLER_DESC desc;
54         desc.Filter = filter;
55         desc.AddressU = wrap;
56         desc.AddressV = wrap;
57         desc.AddressW = wrap;
58         desc.BorderColor = [1, 1, 1, 1];
59         desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
60         desc.MinLOD = 0;
61         desc.MaxLOD = D3D11_FLOAT32_MAX;
62         desc.MipLODBias = 0f;
63         desc.MaxAnisotropy = 1;
64         _hip_d3d_device.CreateSamplerState(&desc, &sampler);
65     }
66     public void setWrapMode(TextureWrapMode mode)
67     {
68         wrap = Hip_D3D11_getWrapMode(mode);
69         updateSamplerState();
70     }
71 
72     protected bool loadImpl(in IImage image)
73     {
74         D3D11_TEXTURE2D_DESC desc;
75         // desc.Format = getFromFromSurface(surface);
76         desc.Usage = D3D11_USAGE_IMMUTABLE;
77         desc.CPUAccessFlags = 0;
78         desc.MipLevels = 1;
79         desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
80         desc.Width = width = image.getWidth;
81         desc.Height = height = image.getHeight;
82 
83         D3D11_SUBRESOURCE_DATA data;
84 
85         const(void)[] pixels;
86         ushort Bpp = 0;
87         int format;
88 
89         switch(image.getBytesPerPixel)
90         {
91             case 1:
92                 if(image.hasPalette)
93                 {
94                     pixels = image.convertPalettizedToRGBA();
95                     Bpp = 4;
96                     format = DXGI_FORMAT_R8G8B8A8_UNORM;
97                 }
98                 else
99                 {
100                     pixels = image.getPixels;
101                     Bpp = 1;
102                     format = DXGI_FORMAT_R8_UNORM;
103                 }
104                 break;
105             case 3:
106             case 4:
107                 pixels = image.getPixels;
108                 Bpp = image.getBytesPerPixel;
109                 format = DXGI_FORMAT_R8G8B8A8_UNORM;
110                 break;
111             case 2:
112             default:
113                 ErrorHandler.assertLazyExit(false, 
114                 "Unsopported bytes per pixel for D3D11 Texture named '"~image.getName~"'");
115         }
116         desc.Format = format;
117         data.pSysMem = cast(void*)pixels.ptr;
118         data.SysMemPitch = image.getWidth*Bpp;
119 
120         _hip_d3d_device.CreateTexture2D(&desc, &data, &texture);
121         _hip_d3d_device.CreateShaderResourceView(texture, cast(D3D11_SHADER_RESOURCE_VIEW_DESC*)null, &resource);
122         updateSamplerState();
123         bind();
124         return false;
125     }
126 
127 
128     ///256 should be enough too
129     private __gshared Hip_D3D11_Texture[256] boundTextures;
130 
131     ///Avoids rebinding to the same sl
132     void bind (int slot = 0)
133     {
134         if(boundTextures[slot] !is this)
135         {
136             _hip_d3d_context.PSSetSamplers(slot, 1, &sampler);
137             _hip_d3d_context.PSSetShaderResources(slot, 1, &resource);
138             boundTextures[slot] = this;
139         }
140     }
141 
142     void unbind (int slot = 0)
143     {
144         if(boundTextures[slot] is this)
145         {
146             _hip_d3d_context.PSSetSamplers(slot, 1, &nullSamplerState);
147             _hip_d3d_context.PSSetShaderResources(slot, 1, &nullSRV);
148             boundTextures[slot] = null;
149         }
150     }
151     
152     int getWidth() const {return width;}
153     int getHeight() const {return height;}
154     
155 }
156 
157 
158 pure int Hip_D3D11_getTextureFilter(TextureFilter min, TextureFilter mag)
159 {
160     with(TextureFilter)
161     {
162         switch(min)
163         {
164             case LINEAR:
165                 if(mag == LINEAR)
166                     return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
167                 break;
168             case NEAREST:
169                 if(mag == LINEAR)
170                     return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
171                 return D3D11_FILTER_MIN_MAG_MIP_POINT;
172             case NEAREST_MIPMAP_LINEAR:
173                 return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
174             default:break;
175         }
176     }
177     return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
178 }
179 
180 pure int Hip_D3D11_getWrapMode(TextureWrapMode mode)
181 {
182     switch(mode) with(TextureWrapMode)
183     {
184         case CLAMP_TO_EDGE:
185             return D3D11_TEXTURE_ADDRESS_CLAMP;
186         case CLAMP_TO_BORDER:
187             return D3D11_TEXTURE_ADDRESS_BORDER;
188         case REPEAT:
189             return D3D11_TEXTURE_ADDRESS_WRAP;
190         case MIRRORED_REPEAT:
191             return D3D11_TEXTURE_ADDRESS_MIRROR;
192         case MIRRORED_CLAMP_TO_EDGE:
193             return D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
194         case UNKNOWN:
195         default:
196             return D3D11_TEXTURE_ADDRESS_WRAP;
197     }
198 }